package com.google.code.coma.loadbalancer.rmi;

import com.google.code.coma.Coma;
import com.google.code.coma.domain.Part;
import com.google.code.coma.loadbalancer.LoadBalancer;
import com.google.code.coma.loadbalancer.entity.Transfer;
import com.google.code.coma.rmi.RMIManager;
import com.google.code.coma.rmi.SelectAllSelector;
import com.google.code.coma.rmi.TypeAmountPartSelector;
import com.google.code.coma.rmi.storage.StorageService;
import org.apache.log4j.Logger;

import java.rmi.RemoteException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 */
public class RmiLoadBalancer extends LoadBalancer {
    private static final Logger log = Logger.getLogger(RmiLoadBalancer.class);

    private List<String> factories;

    public RmiLoadBalancer(String... factories) {
        this.factories = Arrays.asList(factories);
    }

    @Override
    public void run() {
        Map<String, List<Part>> factoriesParts = new HashMap<String, List<Part>>();

        try {
            for (String factory : factories) {
                StorageService<Part> partStorageService = RMIManager.getStorageService(factory + "_" + Coma.PARTS_CONTAINER);
                factoriesParts.put(factory, partStorageService.getSnapshot(new SelectAllSelector<Part>()));

            }

            Transfer transfer = getLoadBalanceTransfers(factoriesParts);

            if (transfer != null) {
                int amount = transfer.getSupply().getAmount() > transfer.getDemand().getAmount() ? transfer.getDemand().getAmount() : transfer.getSupply().getAmount();
                StorageService<Part> from = RMIManager.getStorageService(transfer.getSupply().getFactoryId() + "_" + Coma.PARTS_CONTAINER);
                StorageService<Part> to = RMIManager.getStorageService(transfer.getDemand().getFactoryId() + "_" + Coma.PARTS_CONTAINER);

                List<Part> parts = from.take(new TypeAmountPartSelector(amount, transfer.getSupply().getType()));
                for (Part p : parts) {
					to.add(p);
				}

				if (log.isInfoEnabled()) {
					log.info("Moving " + parts.size() + " " + transfer.getDemand().getType() + "s from " + transfer.getSupply().getFactoryId() + " to " + transfer.getDemand().getFactoryId());
				}
            }


        }catch (RemoteException e) {
            log.error("RMI error", e);
        }
    }
}
